#!/bin/bash
#
#    OsEID-tool
#
#    This is part of OsEID (Open source Electronic ID)
#
#    Copyright (C) 2015-2021 Peter Popovec, popovec.peter@gmail.com
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#    Card initialization and test suite
#
#    Card reader can be forced by env variable for example:
#
#    OsEID_READER='OsEIDsim 00 00' ./OsEID-tool INFO
#
#export OPENSC_DEBUG=255
failecho (){
	tput setaf 1 2>/dev/null;echo $@;tput sgr0 2>/dev/null
}
trueecho (){
	tput setaf 2 2>/dev/null;echo $@;tput sgr0 2>/dev/null
}
warnecho (){
	tput setaf 3 2>/dev/null;echo $@;tput sgr0 2>/dev/null
}
boldecho (){
	tput bold 2>/dev/null;echo $@;tput sgr0 2>/dev/null
}
mechanism2hash () {
	case "${1}" in
	"SHA1-RSA-PKCS"|"SHA1-RSA-PKCS-PSS"|"ECDSA-SHA1")
		echo "sha1";;
	"SHA224-RSA-PKCS"|"SHA224-RSA-PKCS-PSS"|"ECDSA-SHA224")
		echo "sha224";;
	"SHA256-RSA-PKCS"|"SHA256-RSA-PKCS-PSS"|"ECDSA-SHA256")
		echo "sha256";;
	"SHA384-RSA-PKCS"|"SHA384-RSA-PKCS-PSS"|"ECDSA-SHA384")
		echo "sha384";;
	"SHA512-RSA-PKCS"|"SHA512-RSA-PKCS-PSS"|"ECDSA-SHA512")
		echo "sha512";;
	*)
		echo "${1}";;
	esac
}
# return minimal RSA key size for mechanism...
# MyEID card allow us about 40% payload if PKCS1 v1.5 padding is aplied...
test_keysize_mechanism () {
	case "${1}" in
	"SHA1-RSA-PKCS")
		echo "768";;	# 20 bytes HASH and 15 bytes digest info = 35 bytes
	"SHA1-RSA-PKCS-PSS")
		echo "512";;	# no PKCS1 padding no 40% limit
	"SHA256-RSA-PKCS")
		echo "1024";;	# 32 bytes HASH and 19 bytes digest info = 51 bytes
	"SHA256-RSA-PKCS-PSS")
		echo "768";;	# no PKCS1 padding, no 40% limit
	"SHA384-RSA-PKCS")
		echo "1536";;	# 48 bytes HASH and 19 bytes digest info = 67 bytes
	"SHA384-RSA-PKCS-PSS")
		echo "1024";;	# no PKCS1 padding, no 40% limit
	"SHA512-RSA-PKCS")
		echo "2048";;	# 64 bytes HASH and 19 bytes digest info = 83 bytes
	"SHA512-RSA-PKCS-PSS")
		echo "1536";;	#  no PKCS1 padding, no 40% limit
	*)
		echo "65536";;
	esac

}



read_card(){
opensc-tool "${2}" "${3}" -s "${1}" 2>/dev/null|gawk '{
  if($1=="Received"){
	flag=1
	SW1=substr($2,8,2)
	SW2=substr($3,7,2)
	next
  }
  if(flag==1){
	c = NF
	if (c>17) c=17
	for(i=1;i<c;i++)
		printf "%s ",$i
  }
}
END{
	print SW1" "SW2
}'
}

PKCS15-INIT(){
if [ "x${SCReader}" == "x" ]; then
	pkcs15-init ${@}
else
	pkcs15-init -r "${SCReader}" ${@}
fi
}

PKCS15-TOOL(){
if [ "x${SCReader}" == "x" ]; then
	pkcs15-tool ${@}
else
	pkcs15-tool --reader "${SCReader}" ${@}
fi
}

PKCS15-CRYPT(){
if [ "x${SCReader}" == "x" ]; then
	pkcs15-crypt ${@}
else
	pkcs15-crypt -r "${SCReader}" ${@}
fi
}

which gawk pkcs15-init pkcs15-tool sha1sum pkcs15-crypt openssl opensc-tool scriptor tr xxd 2>/dev/null 1>/dev/null
if [ $? -ne 0 ]; then
	echo "unable to found all tools on this system"
	echo "please check: gawk pkcs15-init pkcs15-tool sha1sum pkcs15-crypt openssl opensc-tool scriptor tr xxd"
	exit 1
fi

if [ $# -ge  1 ]; then
	mode=$1
else
	echo "please select mode"
	echo "INFO - print info about card"
	echo "INIT - do initialization of token by pkcs15-init"
	echo "EC-CREATE-KEYS - use openssl to generate EC keys"
	echo "EC-UPLOAD-KEYS - upload EC keys into initialized token"
	echo "EC-GENERATE-KEYS  - generate keys on card" 
	echo "EC-SIGN-TEST - sign sample text by ECDSA operation and verify this signature"
	echo "EC-SIGN-PKCS11-TEST - sign (pkcs11-tool, several mechanisms), check results"
	echo "EC-ECDH-TEST - generate shared secrets and test shared secrets "
	echo "RSA-CREATE-KEYS -  use openssl to generate RSA keys"
	echo "RSA-UPLOAD-KEYS - upload RSA keys into initialized token"
	echo "RSA-GENERATE-KEYS - generate RSA key on card"
	echo "RSA-SIGN-TEST - sign (raw, pkcs15-tool) and verify signature"
	echo "RSA-SIGN-PKCS11-TEST - sign (pkcs11-tool, several mechanisms), check results"
	echo "RSA-DECRYPT-TEST - decrypt test"
	echo "UNWRAP-WRAP-TEST"
	echo "ERASE-CARD - return card to creation state"
	echo "PKCS11-RSA-TEST - pkcs11-tool full test on RSA keys"
	echo "PKCS11-EC-TEST - pkcs11-tool full test on EC keys"
	echo "CSR [key] [subject] - generate certificate signing request"
	echo "CRT [key] [subject] - generate self signed certificate"
	echo "DES-AES-UPLOAD-KEYS - upload 3DES, AES 128 and AES 256 key"
	echo "RND-TEST - test random generator entropy"
	# echo "FAST-TEST"
	# echo "FULL-TEST"
	exit 0
fi
#***************************************************************************************************************************
#
#  Operations that can be taken without a card
#
#***************************************************************************************************************************
function generate_key(){
KSIZE=$1
if [ ! -f keys/rsa${KSIZE}-key.pem.txt ]; then
   echo "Using openssl to generate RSA key modulus ${KSIZE} (exponent 65537 - default)"
   #generate RSA key
   openssl genrsa -out keys/rsa${KSIZE}-key.pem ${KSIZE}
   #extract pub key from key bundle
   openssl rsa -in keys/rsa${KSIZE}-key.pem -pubout -out keys/rsa${KSIZE}-pub.pem
   openssl rsa -in keys/rsa${KSIZE}-key.pem -text -noout >keys/rsa${KSIZE}-key.pem.txt
# optional cert sign request
# openssl req -new -sha256 -key rsa1024-key.pem -out rsa1024-key.csr
# optionaly self sign
# openssl x509 -signkey rsa1024-key.pem -in rsa1024-key.csr -req -days 3650 -out rsa1024-key.crt
fi
}
if [ $mode == "RSA-CREATE-KEYS" ]; then
mkdir -p keys
# card support key len from 512 to 2048 in step of 64 bits, but opensc card-myeid.c driver
# resister only subset of posible keys
# for i in   512 640 768 1024 1440 1536 1664 2048 ; do
 for i in   512 768 1024 1536 2048 ; do
	generate_key $i
 done
 exit 0
fi
#***************************************************************************************************************************


#***************************************************************************************************************************
#openssl ecparam -list_curves
if [ $mode == "EC-CREATE-KEYS" ]; then
mkdir -p keys
echo "Using openssl to generate EC keys"
while read curve oid ;do
  if [ ! -f keys/${curve}-pub.pem ]; then
	echo "Generating EC key ${curve} OID ${oid}"
	#generate EC key
	openssl ecparam -name ${curve} -genkey -noout -out  keys/${curve}-key.pem
	#extract EC pub key from key bundle
	openssl ec -in keys/${curve}-key.pem -pubout >keys/${curve}-pub.pem
	#generate certificate for this key (self signed)
	openssl req -new -x509 -key keys/${curve}-key.pem -out keys/${curve}-cert.pem -days 1095 -subj "/DC=org/DC=OpenSSL/DC=users/UID=123456+CN=nobody test" -multivalue-rdn
	#echo "Converting EC keys into openssh keys"
	# debian ssh 1:6.7p1-3 segfault on this..
	#openssl ec -in keys/prime256v1-key.pem -pubout | ssh-keygen -f /dev/stdin -i -m PKCS8 > keys/id_ecdsa.pub
	#openssl ec -in keys/prime256v1-key.pem  > keys/id_ecdsa
	#optionaly dump
	#openssl ec -text -in keys/${curve}-key.pem
  else
	echo "keys/${curve}-pub.pem already exist"
  fi
done << EOP
prime192v1 1.2.840.10045.3.1.1
prime256v1 1.2.840.10045.3.1.7
secp224r1  1.3.132.0.33
secp384r1  1.3.132.0.34
secp521r1  1.3.132.0.35
secp256k1  1.3.132.0.10
EOP
# same curves
# nistp192/prime192v1/secp192r1 OID 1.2.840.10045.3.1.1
# nistp256/secp256r1/prime256v1 OID 1.2.840.10045.3.1.7
exit 0
fi
#***************************************************************************************************************************
mkdir -p tmp
SCReader=""
SCReaderFlag=""
SCSlot=0
if [ "x${OsEID_READER}" != "x" ]; then
	SCReader=${OsEID_READER}
	SCReaderFlag="-r"
	SCSlot=$(pkcs11-tool -L|gawk -v R="${OsEID_READER}" '{if ($0 ~ R) {print $2;exit}}')
	if [ "x${SCSlot}" == "x" ]; then
		failecho "Unable to determine slot for reader ${OsEID_READER}"
		exit 1
	fi
fi

# Card is needed for rest of operations
CARD_ATR=$(echo "reset"|scriptor -r "${SCReader}" 2>/dev/null)
if [ $? -ne 0 ]; then
	failecho "No card available"
	exit 1
fi
CARD_ATR=$(echo "${CARD_ATR}"|tr '[[:upper:]]' '[[:lower:]]' |gawk '{if($2=="ok:"){for(i=3;i<=NF;i++){printf $i;if(i!=NF)printf":";else print""}}}')

# check card type
CARD_TYPE=""
CARD_INIT=0

echo $CARD_ATR|grep -q "4f:73:45:49:44$"
if [ $? -eq 0 ]; then
	trueecho "Found OsEID card/token, protocol T=0"
	PROTO="T=0"
	CARD_TYPE="OsEID"
fi
echo $CARD_ATR|grep -q "4f:73:45:49:44:"
if [ $? -eq 0 ]; then
	trueecho "Found OsEID card/token, protocol T=1"
	PROTO="T=1"
	CARD_TYPE="OsEID"
fi
echo $CARD_ATR|grep -q "4d:79:45:49:44"
if [ $? -eq 0 ]; then
	warnecho "Found MyEID card"
	PROTO="T=1"
	CARD_TYPE="MyEID"
fi

if [ -z ${CARD_TYPE} ]; then
	warnecho "No OsEID/MyEID card found"
	exit 1
fi


ECC_SIZE_MIN=0
ECC_SIZE_MAX=0

RESP=$(read_card "00 CA 01 A0 00" "${SCReaderFlag}" "${SCReader}")
CARD_SERIAL=$(echo  $RESP|gawk '{for(i=9;i<19;i++) printf $i" ";print""}')
CARD_VERSION=$(echo $RESP|gawk '{for(i=6;i<9;i++) printf $i" ";print""}')
CARD_VER=$(echo "${RESP}"|gawk '{v=0;for(i=6;i<9;i++) {v*=100;v+=strtonum("0x"$i)};printf v;exit}')
if [ $CARD_VER -ge 40000 ]; then
	ECC_SIZE_MIN=192
	ECC_SIZE_MAX=256
	set -e
	CARD_CAPABILITIES=$(read_card "00 CA 01 AA 00" "${SCReaderFlag}" "${SCReader}")
        echo "${CARD_CAPABILITIES}"|gawk ' {
		if (NF != 13) {
			print "unusual response length ("NF") old card?"
			exit 1
		}
	}'
	echo "${CARD_CAPABILITIES}"|gawk ' {
		if ($1 != 1) {
			print "Unknown version of card cap"
			exit 1
		}
	}'
	echo "${CARD_CAPABILITIES}"|gawk ' {
		if ($12 != 90 || $13 != 00){
			print "Unusual status bytes "$12 $13
			exit 1
		}
	}'
	set +e
	ECC_SIZE_MAX=`echo "${CARD_CAPABILITIES}"|gawk ' {
		print strtonum("0x"$10)*256+strtonum("0x"$11)
	}'`
	set +e
fi

# workarounds
if [ "x${CARD_TYPE}" == "xMyEID" ]; then
	case ${CARD_VER} in
		# I am unable to upload or generate prime192V1 key on MyEID 4.5.5 card (Mon 15 Mar 2021)
		40505)
			ECC_SIZE_MIN=256
			;;
	esac
fi

# check if card is initialize (file 2f00 exist)
echo "00 a4 08 00 02 2f 00"|scriptor -r "${SCReader}" -p ${PROTO} 2>/dev/null|grep -q 'Normal processing.\|bytes of response still available' && CARD_INIT=1
X_ver=$(opensc-tool -i)
if [ $? -ne 0 ]; then
	failecho "unable to determine opensc version"
	exit 1
fi
OPENSC_VER=$(echo $X_ver|gawk '/OpenSC/ {split($2,V,".");print V[1]"."V[2]}')
OPENSC_VERSION=$(echo $X_ver|gawk '/OpenSC/ {split($2,V,".");print 1000000*V[1]+1000*V[2]+V[3]}')

ECDH=0
RAWSIGN2048=0

if [ $OPENSC_VERSION -lt 20000 ]; then
	failecho "Your OPENSC version is:"
	opensc-tool -i
	failecho "consider upgrading to a newer version."
	failecho "Multiple features will not be available or will be terminated with an error"
	sleep 5
fi
if [ $OPENSC_VERSION -ge 17000 ]; then
	ECDH=1
fi
if [ $OPENSC_VERSION -ge 18000 ]; then
	RAWSIGN2048=1
fi
if [ $OPENSC_VERSION -gt 22000 ]; then
	warnecho "not tested opensc version detected"
	opensc-tool -i
	warnecho "this code is tested in opensc versions 0.21 .. 0.22"
fi


if [ ${CARD_TYPE} == "OsEID" ]; then
 echo "00 a4 08 00 04 3f 00 50 15"|scriptor -r "${SCReader}" -p ${PROTO} 2>/dev/null|grep -q 'Normal processing.\|bytes of response still available'

 if [ $? -ne 0 ];then
        warnecho "OsEID without DF 5015, creating DF 5015"
        #this is code that generates same security attributes as in originam MyEID card
        #echo "00 E0 00 00 29 62 27 81 02 13 88 82 01 38 83 02 50 15 86 03 33 FF FF 85 02 00 02 8A 01 00 84 0C A0 00 00 00 63 50 4B 43 53 2D 31 35 00 00" |scriptor
        # this is used in OsEID
        echo "00 E0 00 00 29 62 27 81 02 13 88 82 01 38 83 02 50 15 86 03 11 1F FF 85 02 00 02 8A 01 00 84 0C A0 00 00 00 63 50 4B 43 53 2D 31 35 00 00" |scriptor -r "${SCReader}" -p ${PROTO} 2>/dev/null
        if [ $? -ne 0 ]; then
		failecho "unable to create DF 5015"
        fi
 fi
fi
if [ ${CARD_INIT} -eq 1 ]; then
	echo "Found initialized $CARD_TYPE card"
else
	echo "$CARD_TYPE card is not initialized"
fi

#***************************************************************************************************************************
if [ $mode == "INFO" ]; then
   echo "Card serial number: ${CARD_SERIAL}"
   echo "Card version number: ${CARD_VERSION}"

   if [ $CARD_VER -ge 40000 ]; then
        echo "${CARD_CAPABILITIES}"|gawk ' {
		cap=strtonum("0x"$2)*256+strtonum("0x"$3)
		if(and(cap,1))
			printf("RSA algo support\n");
		if(and(cap,2))
			printf("DES algo support\n");
		if(and(cap,4))
			printf("AES algo support\n");
		if(and(cap,8))
			printf("ECDSA and ECDH algo support\n");
		if(and(cap,16))
			printf("GridPIN support\n");
		if(and(cap,32))
			printf("PIV emulation\n");
		printf "Maximum RSA key size %d\n",strtonum("0x"$4)*256+strtonum("0x"$5)
		printf "Maximum DES/3DES key size %d\n",strtonum("0x"$6)*256+strtonum("0x"$7)
		printf "Maximum AES key size %d\n",strtonum("0x"$8)*256+strtonum("0x"$9)
		printf "Maximum ECC key size %d\n",strtonum("0x"$10)*256+strtonum("0x"$11)
	}'
   else
	echo "Card version below 4.0.0, no support for reading card cappabilities"
   fi
   exit 0
fi

#***************************************************************************************************************************



#***************************************************************************************************************************
if [ $mode == "RND-TEST" ]; then
 which ent 2>/dev/null 1>/dev/null
 if [ $? -ne 0 ]; then
     echo "Please install ent - pseudorandom number sequence test program"
     echo "Upstream Homepage: http://www.fourmilab.ch/random/"
     echo "for debian/ubuntu users please install \"ent\" package"
     exit 1
 fi
echo "Please wait .. about 10000 bytes is to be read"
export LC_ALL="C"
TMP=$(mktemp)
TMP="rnd.data"
for i in $(seq 1 1300); do
if [ $PROTO == "T=1" ]; then
	rndCMD='echo "00 84 00 00 08"'
else
	rndCMD='(echo "00 84 00 00 08"; echo "00 c0 00 00 08")'
fi
eval $rndCMD|scriptor "${SCReaderFlag}" "${SCReader}" -p ${PROTO} 2>/dev/null
done|gawk -b '{
if($0 ~ "Normal" )
 {
   printf(".") > "/dev/stderr" 
   for (i=2;i<10;i++)
       printf("%c",strtonum("0x"$i))
 }
}END{
 printf("\n") > "/dev/stderr"
}'  >$TMP
echo "File parsed as the bit stream:"
echo "=============================="
ent -b $TMP
echo ""
echo "File parsed as the byte stream:"
echo "==============================="
ent $TMP
#rm $TMP
exit 0
fi
#***************************************************************************************************************************
if [ "x$mode" == "xFULL-TEST" ] || [ "x$mode" == "xFAST-TEST" ]; then
	set -e
	$0 ERASE-CARD
	echo |$0 INIT
	$0 RSA-CREATE-KEYS
	$0 RSA-UPLOAD-KEYS
	# OsEID card is slow, skip this test for now
	# $0 RSA-GENERATE-KEYS 1024
	$0 RSA-SIGN-TEST
	if [ $mode == "FULL-TEST" ]; then
		$0 RSA-SIGN-PKCS11-TEST
	fi
	$0 RSA-DECRYPT-TEST

	$0 ERASE-CARD
	echo |$0 INIT
	$0 EC-CREATE-KEYS
	$0 EC-UPLOAD-KEYS
	$0 EC-GENERATE-KEYS
	$0 EC-SIGN-TEST
	if [ $mode == "FULL-TEST" ]; then
		$0 EC-SIGN-PKCS11-TEST
	fi
	$0 EC-ECDH-TEST

	$0 DES-AES-UPLOAD-KEYS
	# waiting for #2268
	# $0 UNWRAP-WRAP-TEST

	$0 ERASE-CARD
	exit 0
fi

#***************************************************************************************************************************
if [ $mode == "INIT" ]; then
boldecho "card init"
boldecho "---------"

#pin and puk is not used in this command, but specifying this prevent driver from unnecessarily asking for it several times
if [ $CARD_TYPE == "MyEID" ]; then
	echo "running pkcs15-init, SOPIN=00000000 SOPUK=00000000"
	PKCS15-INIT -C --so-pin 00000000 --so-puk 00000000 --pin 11111111
else
  if [ $CARD_INIT -eq 1 ]; then
	warnecho "Your card is already initialized!"
	exit 0
  fi
  echo "running pkcs15-init, SOPIN=00000000 SOPUK=00000000"
  if [ ! -f /usr/share/opensc/oseid_$OPENSC_VER.profile ]; then
	warnecho "Using myeid profile for OsEID card, please install /usr/share/opensc/oseid_$OPENSC_VER.profile "
	warnecho "Press ENTER continue, or CTRL-C to abort"
	read a
	PKCS15-INIT -C --so-pin 00000000 --so-puk 00000000 --pin 11111111
  else
	PKCS15-INIT -C -c oseid_$OPENSC_VER --so-pin 00000000 --so-puk 00000000 --pin 11111111
  fi
fi
if [ $? -ne 0 ]; then
	failecho "init fail"
	exit 1
fi
echo "pkcs15-init OK"
echo "initializing user (01) PIN=11111111 PUK=11111111"
#this is needed to get access to private key for sign/cipher op
PKCS15-INIT --store-pin --id 01 --pin 11111111 --puk 11111111 --so-pin 00000000
if [ $? -ne 0 ]; then
        failecho "init pin fail"
	exit 2
fi
echo "finalizing card"
#switch card off from init mode 
PKCS15-INIT -F
if [ $? -ne 0 ]; then
        failecho "init - finalizing fail"
        exit 3
fi
trueecho "Card is initialized and activated"
exit 0
fi
# end of phase INIT
#***************************************************************************************************************************

# all next functions need initialized card
if [ $CARD_TYPE == "OsEID" ]; then
	if [ $CARD_INIT -ne 1 ]; then
		warnecho "Your card is not initialized!"
		exit 0
	fi
fi
#***************************************************************************************************************************
if [ $mode == "ERASE-CARD" ]; then
	boldecho "erasing card"
	boldecho "------------"
	if [ x${2} == "xMyEID" ] ; then
		# ACL for MF and DF 5015 is set to same values as on new unitialized MyEID card
		opensc-tool "${SCReaderFlag}" "${SCReader}" -c default -s "00 20 00 03 08 30 30 30 30 30 30 30 30" -s "00 DA 01 E0 08 FF FF 33 3F FF 33 FF FF"
	else
		# This is default for OsEID. MyEID card can use this setup too. SO-PIN is needed only for card erase operation, not for key generation/upload.
		opensc-tool "${SCReaderFlag}" "${SCReader}" -c default -s "00 20 00 03 08 30 30 30 30 30 30 30 30" -s "00 DA 01 E0 08 FF FF 11 3F FF 11 1F FF"
	fi
# pkcs15-tool -E need tty (ioctl to not display pin)..
#	(echo "00000000"|  PKCS15-INIT -E >/dev/tty) >/dev/null
#	if [ $? -eq 0 ];then
#		trueecho "Card is erased"
#	else
#		failecho "unable to erase card"
#		exit 1
#	fi
	exit 0
fi

#***************************************************************************************************************************

if [ $mode == "EC-UPLOAD-KEYS" ]; then
secp256k1_OK=0

boldecho "storing EC key"
boldecho "--------------"
(
# not enabled in opensc myeid driver (0.15 .. 0.22)
#secp224r1  1.3.132.0.33 224
# not supported by opensc myeid driver (0.15 .. 0.22)
#secp256k1 1.3.132.0.10 256
cat <<EOP
prime192v1 1.2.840.10045.3.1.1 192
prime256v1 1.2.840.10045.3.1.7 256
secp384r1  1.3.132.0.34        384
secp521r1  1.3.132.0.35        521
EOP
)|
while read curve oid size ;do
	if [ $size -lt $ECC_SIZE_MIN ]; then continue; fi
	if [ $size -gt $ECC_SIZE_MAX ]; then continue; fi

	if [ $curve == "secp256k1" ]; then
		if [ ! $CARD_TYPE == "OsEID" ]; then
			continue
		fi
	fi
	if [ ! -f keys/${curve}-key.pem ]; then
		continue
	fi
	echo "uploading key ${curve}"
	PKCS15-INIT --store-private-key keys/${curve}-key.pem --key-usage sign --label "${curve}" --auth-id=1 --pin 11111111 --so-pin 00000000
	E=$?
	if [ z${curve} == "zsecp256k1" ]; then
		if [ $E -eq 0 ]; then
			secp256k1_OK=1
			echo "fixing secp256k1 key file"
			P=`PKCS15-TOOL -D|\
			gawk '{if($1 == "Private" && $2=="EC" && $4=="[secp256k1]"){OK=1};if(OK==1 && $1 == "Path"){print substr($3,5,2)" "substr($3,7,2)" "substr($3,9,2)" "substr($3,11,2);exit}}'`
			(
			echo "00 a4 08 00 04 $P"
			echo "00 20 00 01 08 31 31 31 31 31 31 31 31"
			echo "80 da 00 00 01 23"
			)|scriptor "${SCReaderFlag}" "${SCReader}" -p ${PROTO}
		else
			E=0
		fi
	fi
	if [ $E -ne 0 ]; then
	        failecho "fail"
	        exit 1
	fi
	if [ z${curve} == "zsecp256k1" ]; then
	 if [ $secp256k1_OK -eq 0 ]; then
		continue
	 fi
	fi
	echo "uploading self signed cert for key/curve ${curve}"
	PKCS15-INIT -X keys/${curve}-cert.pem --label "${curve}" --auth-id=1 --pin 11111111 --so-pin 00000000
	if [ $? -ne 0 ]; then
	        failecho "fail"
	        exit 2
	fi
done
exit $?
fi

#***************************************************************************************************************************
if [ $mode == "EC-SIGN-TEST" ]; then
mkdir -p tmp
boldecho "testing RAW ECDSA (pkcs15-crypt)"
boldecho "--------------------------------"
#PKCS15-TOOL --list-public-keys|tee /dev/tty |\
PKCS15-TOOL --list-public-keys|
gawk  -F: '{if($1 ~ "FieldLength")OK=1;if($1~"ID" && OK==1){print $2;OK=0}}' |\
while read keyID ; do
  echo "Reading public key "$keyID
  #PKCS15-TOOL --read-public-key $keyID |tee tmp/exported_ec_key.pub
  PKCS15-TOOL --read-public-key $keyID > tmp/exported_ec_key.pub
  echo "generating plain sha1 hash file:"
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" > tmp/testfile.txt
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/testfile.txt
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/testfile.txt
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/testfile.txt
  dd if=/dev/urandom bs=5000 count=1 >> tmp/testfile.txt 2>/dev/null

  # we use openssl dgst to verify signature, hash is needed for sign...
  sha1sum tmp/testfile.txt|cut -d ' ' -f 1|xxd -p -r > tmp/testfile.txt.sha1

  echo "generating RAW ECDSA signature by pkcs15-crypt"
  rm -f tmp/testfile.txt.pkcs11.sha1.sig
  ST=$(date +%s.%N)
  PKCS15-CRYPT --pin 11111111 -k $keyID --signature-format "openssl" -s -i tmp/testfile.txt.sha1 -o tmp/testfile.txt.pkcs11.sha1.sig
  if [ $? -ne 0 ]; then
	failecho "pkcs15-crypt failed"
	exit 1
  fi
  ET=$(date +%s.%N)
  echo "${ET} ${ST}"|gawk '{printf "pkcs15-tool EC SIGN time %f\n",($1 - $2)}'
  echo "testing signature (openssl dgst)"
  openssl dgst -sha1 -verify tmp/exported_ec_key.pub -signature tmp/testfile.txt.pkcs11.sha1.sig tmp/testfile.txt >/dev/null
  if [ $? -ne 0 ]; then
	failecho "openssl signature test fail"
	exit 1
  fi

done # key loop
fi

# pkcs11-tool:
# there is no differense in -m ECDSA or -m ECDSA-SHA1 .. card always get same input
# (OpenSC bug... fixed, commit 6049cb926c980754e18b16794e365a9370f4403e)
# pkcs11-tool --sign --signature-format "openssl" --slot 1 -m ECDSA --input-file sign.this.txt --output-file sign.this.txt.signature
# pkcs11-tool --sign --signature-format "openssl" --slot 1 -m ECDSA-SHA1 --input-file sign.this.txt --output-file sign.this.txt.signature

#***************************************************************************************************************************
if [ $mode == "EC-SIGN-PKCS11-TEST" ]; then
mkdir -p tmp
boldecho "testing ECDSA (pkcs11-tool, several mechanisms)"
boldecho "-----------------------------------------------"

ECC_SIZE_TEST=$(pkcs11-tool --slot-index ${SCSlot} -M 2>/dev/null)
ECC_SIZE_MAX=0
echo ${ECC_SIZE_TEST}|grep -q -F -e 'ECDSA-SHA1' && ECC_SIZE_MAX=256
if [ $ECC_SIZE_MAX -eq 0 ]; then warnecho "card does not support EC funcfions";exit 0;fi
echo ${ECC_SIZE_TEST}|grep -q -F -e 'ECDSA-SHA1, keySize={192,384}' && ECC_SIZE_MAX=384
echo ${ECC_SIZE_TEST}|grep -q -F -e 'ECDSA-SHA1, keySize={192,521}' && ECC_SIZE_MAX=521

PKCS15-TOOL --list-public-keys|\
gawk -v SIZE=$ECC_SIZE_MAX -F: '{if($1 ~ "FieldLength"){if(strtonum($2)<=SIZE){OK=1;fl=$2}else OK=0}if($1~"ID" && OK==1){print $2" "fl;OK=0}}' |\
while read keyID fl; do
  bfl=$[$fl + 7 ]
  bfl=$[bfl / 8 ]
  echo "Reading public key ${keyID}  field length=${fl} (${bfl} bytes)"

  PKCS15-TOOL --read-public-key $keyID > tmp/exported_ec_key.pub

  echo "pkcs11-tool sign and pkcs11-tools --verify"

  echo "test" > tmp/testfile.txt
  rm -f tmp/testfile.txt.pkcs11.sig
  ST=$(date +%s.%N)
  pkcs11-tool --slot-index ${SCSlot} --pin 11111111 --sign  -m ECDSA --signature-format "sequence" --input-file tmp/testfile.txt --output-file tmp/testfile.txt.pkcs11.sig --id $keyID
  if [ $? -ne 0 ]; then
	failecho "pkcs11-tool failed"
	exit 1
  fi
  ET=$(date +%s.%N)
  echo "${ET} ${ST}"|gawk '{printf "pkcs11-tool EC SIGN time %f\n",($1 - $2)}'

  pkcs11-tool --slot-index ${SCSlot} --verify -m ECDSA  --signature-format "sequence" --input-file tmp/testfile.txt --signature-file tmp/testfile.txt.pkcs11.sig --id $keyID|grep -q "^Signature is valid$"
  if [ $? -ne 0 ]; then
	failecho "openssl signature test fail"
	exit 1
  else
	trueecho "Verified OK"
  fi
  echo "pkcs11-tool sign and openssl verify"
  # we using openssl dgst we need to sign digest ..
  echo "generating plain sha1 hash file:"
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" > tmp/testfile.txt
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/testfile.txt
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/testfile.txt
  echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/testfile.txt
  dd if=/dev/urandom bs=5000 count=1 >> tmp/testfile.txt 2>/dev/null
  # we use openssl dgst to verify signature, hash is needed for sign...
  sha1sum tmp/testfile.txt|cut -d ' ' -f 1|xxd -p -r > tmp/testfile.txt.sha1

  rm -f tmp/testfile.txt.pkcs11.sha1.sig
  echo "generating RAW ECDSA signature by pkcs11-tool $bfl"
  rm -f tmp/testfile.txt.pkcs11.sha1.sig
  pkcs11-tool --slot-index ${SCSlot} --pin 11111111 --sign  -m ECDSA --signature-format "openssl" --input-file tmp/testfile.txt.sha1 --output-file tmp/testfile.txt.pkcs11.sha1.sig --id $keyID
  if [ $? -ne 0 ]; then
	failecho "pkcs11-tool failed"
	exit 1
  fi
  echo "testing signature.. (openssl)"
  openssl dgst -sha1 -verify tmp/exported_ec_key.pub -signature tmp/testfile.txt.pkcs11.sha1.sig tmp/testfile.txt >/dev/null
  if [ $? -ne 0 ]; then
	failecho "openssl signature test fail"
	exit 1
  else
	trueecho "Verified OK"
  fi

  for d in sha1 sha224 sha256 sha384 sha512 ; do
	D=$(echo ${d}|tr [:lower:] [:upper:])
	rm -f tmp/testfile.txt.pkcs11.${d}.sig
	# pkcs11 operation corresponds to:
	# openssl dgst -sha1 -sign keys/secp384r1-key.pem -out tmp/testfile.txt.pkcs11.sha1.sig tmp/testfile.txt
	pkcs11-tool --slot-index ${SCSlot} --pin 11111111 --sign --signature-format "openssl" -m ECDSA-${D} --input-file tmp/testfile.txt --output-file tmp/testfile.txt.pkcs11.${d}.sig --id $keyID
	if [ $? -ne 0 ]; then
		failecho "pkcs11-tool failed"
		exit 1
	fi
	echo "testing ECDSA-${D} signature (openssl dgst)"
	openssl dgst -${d} -verify tmp/exported_ec_key.pub -signature tmp/testfile.txt.pkcs11.${d}.sig tmp/testfile.txt >/dev/null
	if [ $? -ne 0 ]; then
		failecho "openssl signature test fail"
		exit 1
	else
		trueecho "Verified OK"
	fi
	echo "testing ECDSA-${D} signature.. (pkcs11-tool)"
	pkcs11-tool --slot-index ${SCSlot} --verify  --signature-format "openssl" -m ECDSA-${D} --id $keyID --input-file tmp/testfile.txt --signature-file tmp/testfile.txt.pkcs11.${d}.sig|grep -q "^Signature is valid$"
	if [ $? -ne 0 ]; then
		failecho "pkcs11-tool --verify failed"
		exit 1
	else
		trueecho "Verified OK"
	fi
  done # digest loop
done # key loop
exit $?
fi
#***************************************************************************************************************************



#***************************************************************************************************************************
if [ $mode == "EC-ECDH-TEST" ]; then
mkdir -p tmp

  if [ $ECDH -ne 1 ]; then
	failecho "ECDH support is working in opensc version 0.17 and above"
	exit 1
  fi
  boldecho "ECDH test"
  boldecho "---------"

(
# not enabled in opensc myeid driver (0.15 .. 0.22)
#secp224r1  1.3.132.0.33 224
# not supported by opensc myeid driver (0.15 .. 0.22)
#secp256k1 1.3.132.0.10 256
cat <<EOP
prime192v1 1.2.840.10045.3.1.1 12 192
prime256v1 1.2.840.10045.3.1.7 13 256
secp384r1  1.3.132.0.34        14 384
secp521r1  1.3.132.0.35        15 521
EOP
)|
  while read curve oid id size ;do
	if [ $size -lt $ECC_SIZE_MIN ]; then continue; fi
	if [ $size -gt $ECC_SIZE_MAX ]; then continue; fi
        echo "Alice: generating key.."
        rm -f tmp/ecdh-${curve}-alice-pub.pem
        rm -f tmp/ecdh-${curve}-alice-pub.der
        #pkcs11-tool --slot-index ${SCSlot} --login --pin 11111111 --keypairgen --key-type EC:${curve} --id ${id} --label ecdh_${curve} --usage-derive --usage-sign
        PKCS15-INIT --generate-key EC:${curve} --label ecdh_${curve} --id ${id} --key-usage sign,keyAgreement --auth-id 1 --pin 11111111 --so-pin 00000000
        echo "Alice: extracting public key from card"
        PKCS15-TOOL --read-public-key  ${id} > tmp/ecdh-${curve}-alice-pub.pem
        openssl ec -in tmp/ecdh-${curve}-alice-pub.pem -out tmp/ecdh-${curve}-alice-pub.der -pubin -pubout -outform der 2>/dev/null
        echo "Bob: key from openssl"
        rm -f tmp/ecdh-${curve}-bob-key.pem
        rm -f tmp/ecdh-${curve}-bob-pub.pem
        rm -f tmp/ecdh-${curve}-bob-pub.der
        openssl ecparam -name ${curve} -genkey -noout -out tmp/ecdh-${curve}-bob-key.pem 2>/dev/null
        echo "Bob: extracting public key"
        openssl ec -in tmp/ecdh-${curve}-bob-key.pem -pubout >tmp/ecdh-${curve}-bob-pub.pem 2>/dev/null
        openssl ec -in tmp/ecdh-${curve}-bob-pub.pem -out tmp/ecdh-${curve}-bob-pub.der -pubin -pubout -outform der 2>/dev/null
        echo "Bob: generates shared key by openssl"
        rm -f tmp/ecdh-${curve}-bob-shared.secret
        openssl pkeyutl -derive -inkey tmp/ecdh-${curve}-bob-key.pem -peerkey tmp/ecdh-${curve}-alice-pub.pem -out tmp/ecdh-${curve}-bob-shared.secret
        echo "Alice: generates shared key by card"
        rm -f tmp/ecdh-${curve}-alice-shared.secret
        pkcs11-tool --slot-index ${SCSlot} --login --pin 11111111 --derive -m ECDH1-DERIVE --id ${id} --input-file tmp/ecdh-${curve}-bob-pub.der \
        --output-file tmp/ecdh-${curve}-alice-shared.secret
        cmp tmp/ecdh-${curve}-bob-shared.secret tmp/ecdh-${curve}-alice-shared.secret
        if [ $? -eq 0 ]; then
               trueecho "shared keys OK"
        else
               failecho "shared keys different!"
               exit 1
        fi
  done
#secp256k1 - there is no easy way generate this key with opensc
fi
#***************************************************************************************************************************



#***************************************************************************************************************************

# Test for EC keys:
if [ $mode == "EC-GENERATE-KEYS" ]; then
boldecho "generating EC keys"
boldecho "------------------"

(
cat << EOP
ec:prime192v1 gen_prime192v1 192
ec:prime256v1 gen_prime256v1 256
ec:secp384r1  gen_secp384r1  384
ec:secp521r1  gen_secp521r1  512
EOP
)|while read curve file_id size ;do
	if [ $size -lt $ECC_SIZE_MIN ]; then continue; fi
	if [ $size -gt $ECC_SIZE_MAX ]; then continue; fi

	echo "generating ${curve} key"
	PKCS15-INIT --generate-key ${curve} --label ${file_id} --auth-id=1 --pin 11111111 --so-pin 00000000
	if [ $? -ne 0 ]; then
		failecho "fail"
		exit 1
	else
		trueecho "OK"
	fi
  done
fi
#***************************************************************************************************************************






#***************************************************************************************************************************

if [ $mode == "RSA-UPLOAD-KEYS" ]; then
boldecho "storing RSA keys"
boldecho "----------------"
err=0
for key in $(ls keys/rsa*-key.pem); do
	echo "${key}"
	L=$(echo "${key}"|gawk -F'-' '{print "key_"strtonum(substr($1,9))}')
	PKCS15-INIT --store-private-key "${key}" --key-usage sign,decrypt --label "${L}" --auth-id=1 --pin 11111111 --so-pin 00000000
	if [ $? -ne 0 ]; then
		err=$[$err + 1 ]
		failecho "Unable to upload RSA key ${key}"
	fi
done
if [ $err -gt 0 ]; then
	failecho "RSA-UPLOAD-KEYS: ${err} errors!"
	exit 1
fi
fi
#***************************************************************************************************************************
if [ $mode == "RSA-GENERATE-KEYS" ]; then
if [ $# -le  1 ]; then
 echo "generating 1024 RSA key (this may take a long long time - maybe over 30 minutes)"
 echo "You can break this command by CTRL-C or continue by ENTER"
 read
 KSIZE=1024
else
 KSIZE=$[$2 + 0 ]
 fail=1
 for i in 512 768 1024 1536 2048 ; do
  if [ $i == ${KSIZE} ]; then
	fail=0;
  fi
 done
 if [ $fail == 1 ]; then
	echo "Wrong RSA key size"
	exit 0
 fi
fi
echo "Generating ${KSIZE} RSA key"
PKCS15-INIT --generate-key "rsa/${KSIZE}" --label "gen_rsa_${KSIZE}" --key-usage sign,decrypt --auth-id 1 --pin 11111111 --so-pin 00000000
if [ $? -ne 0 ]; then
	failecho "fail"
	exit 1
fi
echo "Listing keys:"
PKCS15-TOOL -k
fi
#***************************************************************************************************************************
if [ $mode == "RSA-SIGN-TEST" ]; then
mkdir -p tmp
boldecho "testing RSA signature (pkcs15-crypt)"
boldecho "------------------------------------"

echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" > tmp/rsa_sign_testfile.txt
echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/rsa_sign_testfile.txt
echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/rsa_sign_testfile.txt
echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/rsa_sign_testfile.txt
dd if=/dev/urandom bs=5000 count=1 >> tmp/rsa_sign_testfile.txt 2>/dev/null


#list all RSA keys 

err=0
for keyID in $(PKCS15-TOOL --list-public-keys|gawk -F: '{if($1 ~ "ModLength"){if(strtonum($2)>=512)OK=1;else OK=0};if($1~"ID" && OK==1){print $2;OK=0}}') ; do
echo "Reading public key "$keyID
#PKCS15-TOOL --read-public-key $keyID |tee tmp/exported_rsa_key.pub
PKCS15-TOOL --read-public-key $keyID > tmp/exported_rsa_key.pub
LEN=$(openssl rsa -in tmp/exported_rsa_key.pub -text -noout -pubin |gawk '/Public-Key:/ {print $1}' FPAT='[0-9]+')
if [ "x${LEN}" == "x" ]; then
	exit 1
fi
LEN=$[$LEN / 8 ]
dd if=tmp/rsa_sign_testfile.txt bs=$LEN count=1 of=tmp/rsa_sign_testfile_${LEN}.txt 2>/dev/null

# MyEID support key len in step 64 bits, maximal raw sign is then 248 bytes
# OsEID is without this limit .. but MyEID interface does allow transfer
# maximum 250 bytes of data (APDU max 255, 5 bytes for CLA, CMD, P1, P1 LEN)
# raw 2048 bit signature is supported in OpenSC git version
# (https://github.com/OpenSC/OpenSC/commit/deab9cce73377f973d2020ab5ab7adc302018bf6)
if [ $LEN -lt 249 ] || [ $RAWSIGN2048 -eq 1 ] ; then
	echo "using pkcs15-crypt to sign RAW message, message length $LEN"
	PKCS15-CRYPT --pin 11111111 -k $keyID  -s \
	   -i tmp/rsa_sign_testfile_${LEN}.txt \
	   -o tmp/rsa_sign_testfile_${LEN}.txt.sign
	if [ $? -eq 0 ]; then
		echo "testing signature (openssl rsautl)"
		openssl rsautl -raw -pubin -verify \
			-inkey tmp/exported_rsa_key.pub \
			-in tmp/rsa_sign_testfile_${LEN}.txt.sign \
			-out tmp/rsa_sign_testfile_${LEN}.txt.check
		cmp tmp/rsa_sign_testfile_${LEN}.txt.check tmp/rsa_sign_testfile_${LEN}.txt
		if [ $? -eq 0 ]; then
			trueecho "Verified OK"
		else
			failecho "RAW sign fail "
			err=$[$err + 1 ]
		fi
	else
		failecho "pkcs15-crypt fail"
		err=$[$err + 1 ]
	fi
else
	warnecho "message over 248 bytes, skipping RAW sign operation"
	warnecho "support for RAW 2048 RSA signature is available from opensc 0.18"
fi
done
if [ $err -gt 0 ]; then
	failecho "RSA-SIGN-TEST: ${err} errors!"
	exit 1
fi
fi
#***************************************************************************************************************************
if [ $mode == "RSA-SIGN-PKCS11-TEST" ]; then
mkdir -p tmp
boldecho "testing RSA signature (pkcs11-tool, several mechanisms)"
boldecho "-------------------------------------------------------"

echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" > tmp/rsa_sign_testfile.txt
echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/rsa_sign_testfile.txt
echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/rsa_sign_testfile.txt
echo "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" >> tmp/rsa_sign_testfile.txt
dd if=/dev/urandom bs=5000 count=1 >> tmp/rsa_sign_testfile.txt 2>/dev/null

# create hashes (to test PSS)
openssl dgst -sha1  -binary -out tmp/rsa_sign_testfile.txt.sha1 tmp/rsa_sign_testfile.txt
openssl dgst -sha256 -binary -out tmp/rsa_sign_testfile.txt.sha256 tmp/rsa_sign_testfile.txt
openssl dgst -sha384 -binary -out tmp/rsa_sign_testfile.txt.sha384 tmp/rsa_sign_testfile.txt
openssl dgst -sha512 -binary -out tmp/rsa_sign_testfile.txt.sha512 tmp/rsa_sign_testfile.txt

# list all RSA keys

err=0
for keyID in $(PKCS15-TOOL --list-public-keys|gawk -F: '{if($1 ~ "ModLength"){if(strtonum($2)>=512)OK=1;else OK=0};if($1~"ID" && OK==1){print $2;OK=0}}') ; do
echo "Reading public key "$keyID
PKCS15-TOOL --read-public-key $keyID |tee tmp/exported_rsa_key.pub
LEN=$(openssl rsa -in tmp/exported_rsa_key.pub -text -noout -pubin |gawk '/Public-Key:/ {print $1}' FPAT='[0-9]+')
if [ "x${LEN}" == "x" ]; then
	exit 1
fi
BITLEN=$LEN
LEN=$[$[$LEN + 7 ] / 8 ]

dd if=tmp/rsa_sign_testfile.txt bs=${LEN} count=1 of=tmp/rsa_sign_testfile_${LEN}.txt 2>/dev/null
# RSA-X-509
echo "using pkcs11 interface to sign message, mechanism RSA-X-509"
rm -f  tmp/rsa_sign_testfile.txt.sign
echo -n "ttt" > tmp/rsa_sign_testfile_short.txt
gawk -b -v LEN=${LEN} '{for(i=0;i<LEN-1-length($0);i++)printf("%c",0);printf("%c%s",0,$0);exit}' tmp/rsa_sign_testfile_short.txt >tmp/rsa_sign_testfile_x509.txt
pkcs11-tool --slot-index ${SCSlot} --sign  -m RSA-X-509\
	--id $keyID \
	--input-file tmp/rsa_sign_testfile_x509.txt \
	--output-file tmp/rsa_sign_testfile.txt.sign \
	--pin 11111111
if [ $? -eq 0 ]; then
	echo "testing RSA-X-509 signature (openssl rsautl)"
	openssl rsautl -raw -verify -pubin -inkey tmp/exported_rsa_key.pub < tmp/rsa_sign_testfile.txt.sign > tmp/rsa_sign_testfile.txt.sign_verify
	cmp tmp/rsa_sign_testfile_x509.txt tmp/rsa_sign_testfile.txt.sign_verify
	if [ $?	-ne 0 ]; then
		failecho "RSA-X-509 signature fail"
		err=$[$err + 1 ]
		hd tmp/rsa_sign_testfile_x509.txt
		hd tmp/rsa_sign_testfile.txt.sign_verify
	else
		trueecho "Verified OK"
	fi
else
	failecho "pkcs11 fail"
	err=$[$err + 1 ]
fi

# RSA-PKCS
echo "using pkcs11 interface to sign message, mechanism RSA-PKCS"
rm -f tmp/rsa_sign_testfile.txt.sign
rm -f tmp/rsa_sign_testfile.txt.sign_verify1 tmp/rsa_sign_testfile.txt.sign_verify2

echo -n "ttt" > tmp/rsa_sign_testfile_short.txt
pkcs11-tool --slot-index ${SCSlot} --sign  -m RSA-PKCS \
	--id $keyID \
	--input-file tmp/rsa_sign_testfile_short.txt \
	--output-file tmp/rsa_sign_testfile.txt.sign \
	--pin 11111111
if [ $? -eq 0 ]; then
	echo "testing RSA-PKCS signature (openssl rsautl)"
	openssl rsautl -raw -verify -pubin -inkey tmp/exported_rsa_key.pub < tmp/rsa_sign_testfile.txt.sign > tmp/rsa_sign_testfile.txt.sign_verify1
	# create testfile with padding...
	gawk -b -v LEN=${LEN} '{LEN=LEN-3;LEN=LEN-length($0);printf("%c%c",0,1);for(i=0;i<LEN;i++)printf("%c",255);printf("%c%s",0,$0);exit}' tmp/rsa_sign_testfile_short.txt >tmp/rsa_sign_testfile.txt.sign_verify2
	cmp tmp/rsa_sign_testfile.txt.sign_verify1 tmp/rsa_sign_testfile.txt.sign_verify2
	if [ $?	-ne 0 ]; then
		failecho "RSA-PKCS signature fail"
		err=$[$err + 1 ]
		hd tmp/rsa_sign_testfile.txt.sign_verify1
		hd tmp/rsa_sign_testfile.txt.sign_verify2
	else
		trueecho "Verified OK"
	fi
else
	failecho "pkcs11 fail"
	err=$[$err + 1 ]
fi


for MECHANISM in "SHA1-RSA-PKCS" "SHA256-RSA-PKCS" "SHA384-RSA-PKCS" "SHA512-RSA-PKCS" ; do
RLEN=$(test_keysize_mechanism "${MECHANISM}")
if [ $RLEN -gt $BITLEN ]; then
	continue
fi
echo "using pkcs11 interface to sign message, mechanism ${MECHANISM}"
file_hash=$(mechanism2hash "${MECHANISM}")
rm -f  tmp/rsa_sign_testfile.txt.sign
# use pkcs11-tool to do same as:
# openssl dgst -sha1 -sign _private_key.pem_ --input-file tmp/rsa_sign_testfile.txt --output-file tmp/rsa_sign_testfile.txt.sign
pkcs11-tool --slot-index ${SCSlot} --sign  -m "${MECHANISM}" \
	--id $keyID \
	--input-file tmp/rsa_sign_testfile.txt \
	--output-file tmp/rsa_sign_testfile.txt.sign \
	--pin 11111111
if [ $? -eq 0 ]; then
	echo "sinature verification (openssl dgst)"
#	openssl rsautl -raw -verify -pubin -inkey tmp/exported_rsa_key.pub < tmp/rsa_sign_testfile.txt.sign |hd
	openssl dgst "-${file_hash}" -verify tmp/exported_rsa_key.pub -signature tmp/rsa_sign_testfile.txt.sign tmp/rsa_sign_testfile.txt >/dev/null
	if [ $?	-ne 0 ]; then
		failecho "openssl signature test fail"
		err=$[$err + 1 ]
	else
		trueecho "Verified OK"
	fi
	echo "sinature verification (pkcs11-tool)"
	pkcs11-tool --slot-index ${SCSlot} --verify  -m "${MECHANISM}" --id $keyID --input-file tmp/rsa_sign_testfile.txt --signature-file tmp/rsa_sign_testfile.txt.sign|grep -q "^Signature is valid$"
	if [ $? -ne 0 ]; then
		failecho "pkcs11-tool --verify failed"
		err=$[$err + 1 ]
	else
		trueecho "Verified OK"
	fi

else
	failecho "pkcs11 fail"
	err=$[$err + 1 ]
fi

done	# mechanism loop (no PSS mechanisms)


# test PSS signature
for MECHANISM in "SHA1-RSA-PKCS-PSS" "SHA256-RSA-PKCS-PSS" "SHA384-RSA-PKCS-PSS" "SHA512-RSA-PKCS-PSS" ; do
RLEN=$(test_keysize_mechanism "${MECHANISM}")
if [ $RLEN -gt $BITLEN ]; then
        continue
fi
file_hash=$(mechanism2hash "${MECHANISM}")
rm -f tmp/rsa_sign_testfile.txt.${file_hash}.sign
# use pkcs11-tool to do same operation as:
# openssl pkeyutl -sign -pkeyopt digest:sha1 -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1 \
#	-in tmp/rsa_sign_testfile.txt.sha1 \
#	-inkey _private_key.pem_ \
#	-out tmp/rsa_sign_testfile.txt.sha1.sign
echo "using pkcs11 interface to sign message, mechanism ${MECHANISM}"
pkcs11-tool --slot-index ${SCSlot} --sign  -m "${MECHANISM}" \
	--id $keyID \
	--input-file tmp/rsa_sign_testfile.txt \
	--output-file tmp/rsa_sign_testfile.txt.${file_hash}.sign \
	--pin 11111111
if [ $? -eq 0 ]; then
#	openssl rsautl -raw -verify -pubin -inkey tmp/exported_rsa_key.pub < tmp/rsa_sign_testfile.txt.${file_hash}.sign |hd
	openssl pkeyutl -verify -in tmp/rsa_sign_testfile.txt.${file_hash} \
		 -sigfile tmp/rsa_sign_testfile.txt.${file_hash}.sign \
		 -pkeyopt rsa_padding_mode:pss \
		 -pkeyopt rsa_pss_saltlen:-1 \
		 -pkeyopt digest:${file_hash} \
		 -pubin -inkey tmp/exported_rsa_key.pub
	if [ $?	-ne 0 ]; then
		failecho "openssl signature test fail"
		err=$[$err + 1 ]
	else
		trueecho "Verified OK"
	fi
	echo "sinature verification (pkcs11-tool)"
	pkcs11-tool --slot-index ${SCSlot} --verify  -m "${MECHANISM}" --id $keyID --input-file tmp/rsa_sign_testfile.txt --signature-file tmp/rsa_sign_testfile.txt.${file_hash}.sign|grep -q "^Signature is valid$"
	if [ $? -ne 0 ]; then
		failecho "pkcs11-tool --verify failed"
		err=$[$err + 1 ]
        else
		trueecho "Verified OK"
	fi
else
	failecho "pkcs11 fail"
	err=$[$err + 1 ]
fi
done # mechanism loop (PSS mechanisms)
done    # key loop
if [ $err -gt 0 ]; then
	failecho "RSA-SIGN-PKCS11-TEST: ${err} errors!"
	exit 1
fi
fi
#***************************************************************************************************************************
if [ $mode == "RSA-DECRYPT-TEST" ]; then
boldecho "testing RSA decrypt operation"
boldecho "-----------------------------"
mkdir -p tmp

echo "testtesttesttesttest" > tmp/rsa_decrypt_testfile.txt

err=0
for keyID in $(PKCS15-TOOL --list-public-keys|gawk -F: '{if($1 ~ "ModLength"){if(strtonum($2)>=512)OK=1;else OK=0};if($1~"ID" && OK==1){print $2;OK=0}}') ; do
echo "Reading public key "$keyID
#PKCS15-TOOL --read-public-key $keyID |tee tmp/exported_rsa_key.pub
PKCS15-TOOL --read-public-key $keyID > tmp/exported_rsa_key.pub
if [ $? -ne 0 ]; then
	failecho "pkcs15-tool failed"
	exit 1
fi
openssl rsa -pubin -in tmp/exported_rsa_key.pub -text -noout|grep bit
echo "using openssl to encrypt test message"
openssl rsautl -encrypt -pubin -inkey tmp/exported_rsa_key.pub -in tmp/rsa_decrypt_testfile.txt -out tmp/rsa_encrypted_testfile.txt || exit 1
echo "using pkcs11 interface to decrypt test message"
rm -f  tmp/rsa_pkcs11_tool_decrypted_testfile.txt

ST=$(date +%s.%N)
pkcs11-tool --slot-index ${SCSlot} --decrypt \
	--id $keyID \
	--input-file tmp/rsa_encrypted_testfile.txt \
	--output-file tmp/rsa_pkcs11_tool_decrypted_testfile.txt \
	-m RSA-PKCS --pin 11111111
if [ $? -ne 0 ]; then
	failecho "pkcs11-tool failed"
	exit 1
fi
ET=$(date +%s.%N)
echo "${ET} ${ST}"|gawk '{printf "pkcs11-tool RSA DECRYPT time %f\n",($1 - $2)}'

cmp tmp/rsa_decrypt_testfile.txt tmp/rsa_pkcs11_tool_decrypted_testfile.txt
if [ $? -eq 0 ]; then
	trueecho "OK"
else
	failecho "error in decrypt"
	err=$[$err + 1 ]
fi
done
if [ $err -gt 0 ]; then
	failecho "RSA-DECRYPT-TEST: ${err} errors!"
	exit 1
fi
fi
#***************************************************************************************************************************
if [ $mode == "PKCS11-RSA-TEST" ]; then
	pkcs11-tool --slot-index ${SCSlot} --login --test --pin=11111111
	exit 0
fi
#***************************************************************************************************************************
if [ $mode == "PKCS11-EC-TEST" ]; then

	ECC_SIZE_TEST=$(pkcs11-tool --slot-index ${SCSlot} -M 2>/dev/null)
	ECC_SIZE_MAX=0
	echo ${ECC_SIZE_TEST}|grep -q -F -e 'ECDSA-SHA1' && ECC_SIZE_MAX=256
	if [ $ECC_SIZE_MAX -eq 0 ]; then warnecho "card does not support EC funcfions";exit 0;fi
	echo ${ECC_SIZE_TEST}|grep -q -F -e 'ECDSA-SHA1, keySize={192,384}' && ECC_SIZE_MAX=384
	echo ${ECC_SIZE_TEST}|grep -q -F -e 'ECDSA-SHA1, keySize={192,521}' && ECC_SIZE_MAX=521

	pkcs11-tool --slot-index ${SCSlot} --test-ec --login --pin 11111111 --id 11 --key-type EC:secp192r1
	pkcs11-tool --slot-index ${SCSlot} --test-ec --login --pin 11111111 --id 11 --key-type EC:secp256r1
	if [ $ECC_SIZE_MAX -ge 384 ]; then
		pkcs11-tool --slot-index ${SCSlot} --test-ec --login --pin 11111111 --id 11 --key-type EC:secp384r1
	fi
	if [ $ECC_SIZE_MAX -ge 521 ]; then
		pkcs11-tool --slot-index ${SCSlot} --test-ec --login --pin 11111111 --id 11 --key-type EC:secp521r1
	fi
	exit 0
fi
#***************************************************************************************************************************
if [ $mode == "DES-AES-UPLOAD-KEYS" ]; then
	boldecho "Uploading AES/DES keys"
	boldecho "----------------------"
	err=0
	echo "pppppppppppppppppppppppppppppppp"|dd count=1 bs=16 > tmp/aes_128.key 2>/dev/null
	echo "pppppppppppppppppppppppppppppppp"|dd count=1 bs=24 > tmp/aes_192.key 2>/dev/null
	echo "pppppppppppppppppppppppppppppppp"|dd count=1 bs=32 > tmp/aes_256.key 2>/dev/null
	echo "pppppppppppppppppppppppppppppppp"|dd count=1 bs=8  > tmp/des_64.key  2>/dev/null
	echo "pppppppppppppppppppppppppppppppp"|dd count=1 bs=16 > tmp/des_128.key 2>/dev/null
	echo "pppppppppppppppppppppppppppppppp"|dd count=1 bs=24 > tmp/des_192.key 2>/dev/null
# MyEID DES upload is fixed by 6d98f8c8d8d3c6b56e3a600d46a56bfcc938bc68
# MyEID support for DES is not checked here.. (version 3.3.3 does not support DES ...)
	if [ $OPENSC_VERSION -ge 20000 ]; then
		echo "DES 64:"
		PKCS15-INIT --store-secret-key tmp/des_64.key --secret-key-algorithm des/64 --id 80 --auth-id=1 --pin 11111111 --so-pin 00000000
		if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	fi
# 2des ..
	echo "3DES 128:"
	PKCS15-INIT --store-secret-key tmp/des_128.key --secret-key-algorithm 3des/128 --id 81 --auth-id=1 --pin 11111111 --so-pin 00000000
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
# 3des = 3des/192
	echo "3DES 192:"
#	PKCS15-INIT --store-secret-key tmp/des_192.key --secret-key-algorithm 3des/192 --id 82 --auth-id=1 --pin 11111111 --so-pin 00000000
	PKCS15-INIT --store-secret-key tmp/des_192.key --secret-key-algorithm 3des     --id 82 --auth-id=1 --pin 11111111 --so-pin 00000000
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	echo "AES 128:"
	PKCS15-INIT --store-secret-key tmp/aes_128.key --secret-key-algorithm aes128   --id 85 --auth-id=1 --pin 11111111 --so-pin 00000000
	if [ $? -ne 0 ]; then err=$[$err + 1 ] ;failecho "FAIL";else trueecho "OK"; fi
# MyEID driver does not support this, opensc must be patched to use AES192 with OsEID card
#	if [ ${CARD_TYPE} == "OsEID" ]; then
#		echo "AES 192:"
#		PKCS15-INIT --store-secret-key tmp/aes_192.key --secret-key-algorithm aes192 --id 86 --auth-id=1 --pin 11111111 --so-pin 00000000
#		if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
#	fi
	echo "AES 256:"
	PKCS15-INIT --store-secret-key tmp/aes_256.key --secret-key-algorithm aes256 --id 87 --auth-id=1 --pin 11111111 --so-pin 00000000 --key-usage keyEncipherment,dataEncipherment
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	if [ $err -gt 0 ]; then
		failecho "Symetric key upload: ${err} errors!"
		exit 1
	fi
	echo "AES 256, extractable:"
	PKCS15-INIT --store-secret-key tmp/aes_256.key --secret-key-algorithm aes256 --id 88 --auth-id=1 --pin 11111111 --so-pin 00000000 --extractable
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	if [ $err -gt 0 ]; then
		failecho "Symetric key upload: ${err} errors!"
		exit 1
	fi
	exit 0
fi
#
if [ $mode == "DES-AES-TEST" ]; then
	boldecho "DES AES test"
	boldecho "------------"
	err=0
	echo "AES-ECB and AES-CBC test"
	VECTOR="00000000000000000000000000000000"
	dd if=/dev/random bs=32 count=1 >tmp/aes_plain.data 2>/dev/null
	openssl enc -aes-128-cbc -nopad -in tmp/aes_plain.data -out tmp/aes_ciphertext_openssl.data -iv "${VECTOR}" -K "70707070707070707070707070707070"
	pkcs11-tool --slot-index ${SCSlot} --login --pin=11111111 \
		--decrypt --id 85 -m AES-CBC --iv "${VECTOR}" \
	        --input-file tmp/aes_ciphertext_openssl.data --output-file tmp/aes_plain_test.data
	cmp tmp/aes_plain.data tmp/aes_plain_test.data
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	if [ $err -gt 0 ]; then
		failecho "Symetric key test: ${err} errors!"
		exit 1
	fi
	exit 0
fi
#***************************************************************************************************************************
if [ $mode == "UNWRAP-WRAP-TEST" ]; then
	# waiting for #2268....
	boldecho "UNWRAP/WRAP test"
	boldecho "----------------"
	err=0
	# Sun 04 Apr 2021 08:24:44 AM CEST (OpenSC GIT 1a3666364dc434f4bbfd4154012c5d4e4dc23cb2 + https://github.com/OpenSC/OpenSC/pull/2268)
	# tested - MyEID 4.5.5 - erased card, security attributes: 3f00[11 3F FF], 5015[11 1F FF]
	echo "UNWRAP and WRAP test /unwrap: RSA-PKCS, AES-CBC-PAD/wrap: AES-CBC-PAD/"
	echo "generating RSA key (token)"
	PKCS15-INIT --generate-key "rsa:1024" --label "gen_rsa_unwrap" --key-usage keyEncipherment,decrypt --id 70 --auth-id 1 --pin 11111111 --so-pin 00000000
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	echo "reading public part of RSA key"
	pkcs11-tool --slot-index ${SCSlot} --login --pin=11111111 --read-object --type pubkey --id=70 -o tmp/rsa_pub_unwrap.key
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi

	echo "creating 1st AES key"
	KEY="000102030405060708090a0b0c0d0e0f"
	echo -n $KEY|xxd -p -r > tmp/aes_plain_test.key
	echo "Using generated RSA key - public key - to wrap AES key (openssl, mechanism RSA-PKCS)"
	openssl rsautl -encrypt -pubin --keyform der -inkey tmp/rsa_pub_unwrap.key -in tmp/aes_plain_test.key -out tmp/aes_wrapped_test.key
	echo "Unwrapping AES key on token (mechanism RSA-PKCS)"
	pkcs11-tool --slot-index ${SCSlot} --login --pin=11111111 --unwrap --mechanism RSA-PKCS --id 70 -i tmp/aes_wrapped_test.key --key-type AES:16 \
		--application-id 75 --application-label "unwraped-aes-key" --usage-wrap
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi

	echo "creating 2nd AES key"
	KEY2="ff0102030405060708090a0b0c0d0e0f"
	echo -n $KEY2|xxd -p -r > tmp/aes_plain_test2.key
	VECTOR="07070707070707070707070707070707"
	echo "Wrappinf 2nd AES key by 1st AES key (openssl, mechanism AES-CBC-PAD)"
	openssl enc -aes-128-cbc -in tmp/aes_plain_test2.key -out tmp/aes_wrapped_by_aes.key -iv "${VECTOR}" -K $KEY
	echo "Using 1st AES key to unwrap 2nd AES key on token (mechanism AES-CBC-PAD)"
	pkcs11-tool --slot-index ${SCSlot} --login --pin=11111111 --unwrap --mechanism AES-CBC-PAD --id 75 -i tmp/aes_wrapped_by_aes.key --iv $VECTOR \
		--key-type AES:16 --extractable --application-id 76 --application-label "unwraped-aes-key2" --usage-decrypt
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi

	echo "wrapping 2nd AES key by 1st AES key (token)"
	pkcs11-tool --slot-index ${SCSlot} --login --pin=11111111 --wrap --mechanism AES-CBC-PAD --id 75 --application-id 76 \
		--output-file tmp/exported_aes.key --iv "00000000000000000000000000000000"
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	echo "comparing..."
	openssl enc -aes-128-cbc -d -in tmp/exported_aes.key -iv "00000000000000000000000000000000" -K $KEY -out tmp/check_wrapped.key
	cmp tmp/check_wrapped.key tmp/aes_plain_test2.key
	if [ $? -ne 0 ]; then err=$[$err + 1 ]; failecho "FAIL";else trueecho "OK"; fi
	if [ $err -gt 0 ]; then
		failecho "UNWRAP/WRAP test failed"
		exit 1
	fi
	exit 0
fi
#***************************************************************************************************************************
# compatibility with old version ...
if [ $mode == "RSA-CSR" ]; then
	mode="CSR"
fi
if [ $mode == "CSR" ] || [ $mode == "CRT" ]; then
V=0
openssl version -v | fgrep -q 'OpenSSL 1.1' && V=11
if [ $V -eq 0 ]; then
	echo "Unable to determine openssl version, or your openssl is too old"
	exit 1
fi

if [ $# -lt  2 ]; then
	echo "Please specify key ID (use pkcs15-tool -k to read keys)"
	exit 1
fi
keyReq=$2

if [ $# -gt  2 ]; then
	SUBJ="${3}"
else
	SUBJ="/C=EX/ST=Example/L=Example/O=example/CN=Joe Random\/emailAddress=joe.random@example.example/"
	echo "You can specify subj into csr for example:"
	echo "   $0 $1 $2 \"/O=EX/ST=Example/L=Example/O=example/CN=Joe Random\/emailAddress=joe.random@example.example/\""
fi
echo "Using ${SUBJ}"


echo "searching key ${keyReq}"
mkdir -p tmp

#list all RSA keys 
PKCS15-TOOL --list-public-keys|\
gawk -F: '{if($1~"ID")print $2 }'|\
while read keyID; do
 if [ "${keyReq}" == "${keyID}" ];then
	echo "Key found"
	echo "creating openssl config"

cat <<EOP >tmp/openssl.conf
openssl_conf            = openssl_def

[openssl_def]
engines = engine_section

[engine_section]
pkcs11 = pkcs11_section

[pkcs11_section]
engine_id = pkcs11
EOP
echo "MODULE_PATH = /usr/lib/`uname -m`-linux-gnu/opensc-pkcs11.so" >> tmp/openssl.conf
DP="/usr/lib/`uname -m`-linux-gnu/openssl-1.0.1/engines/libpkcs11.so"
cat <<EOP >>tmp/openssl.conf
init = 0

[req]
distinguished_name = req_distinguished_name
[req_distinguished_name]
EOP


if [ $mode == "CSR" ]; then
echo "generating CSR for key ID ${keyID} into file ${keyID}.csr with subject ${SUBJ}"
rm -f ${keyID}.csr
#warnecho "Please ignore message 'No private keys found.'"
openssl req -config tmp/openssl.conf -new \
-engine pkcs11 \
-key slot_${SCSlot}-id_${keyID} \
-keyform engine \
-out ${keyID}.csr -text \
-multivalue-rdn \
-subj "${SUBJ}"
if [ $? -ne 0 ];then
	failecho "CSR generation fail"
	exit 1
fi

echo ".........................................................." 
openssl req -in ${keyID}.csr -text  -noout
echo " "
echo "you can copy ${keyID}.csr into easy-rsa/keys directory and do sign with pkitool --sign ${keyID}"
echo "(easy rsa may generate error/warning about missing key, this can be ignored)"
echo "Then import certificate into card from easy-rsa/keys/${keyID}.crt by command:"
echo "pkcs15-init --store-certificate ${keyID}.crt"
echo ".........................................................." 

else
echo "generating self signed CRT for key ID ${keyID} into file ${keyID}.crt with subject ${SUBJ}"
rm -f ${keyID}.crt
#warnecho "Please ignore message 'No private keys found.'"
openssl req -config tmp/openssl.conf -new \
-x509 \
-engine pkcs11 \
-key slot_${SCSlot}-id_${keyID} \
-keyform engine \
-out ${keyID}.crt -text \
-multivalue-rdn \
-subj "${SUBJ}"

echo ".........................................................."
openssl x509 -in ${keyID}.crt -text  -noout
echo " "
echo "You can import self signed certificate into card by command:"
echo "pkcs15-init --store-certificate ${keyID}.crt"
echo ".........................................................."
fi

fi
done
fi # CRT, CSR
#***************************************************************************************************************************
